package xing.application.service.page;

import com.querydsl.core.Tuple;
import jdk.nashorn.internal.codegen.CompilerConstants;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.codec.binary.Base64;
//import org.apache.commons.codec.binary.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import xing.application.service.BaseService;
import xing.application.service.page.dto.MyTemplate;
import xing.domain.page.*;
import xing.domain.page.dto.ModuleItemDto;
import xing.domain.page.enums.ContentRefType;
import xing.domain.page.enums.ModuleType;
import xing.domain.page.enums.TemplateType;
import xing.infrastructure.data.CallResult;
import xing.infrastructure.util.IdWorker;
import xing.repository.page.PageContentItemRepository;
import xing.repository.page.PageTemplateRepository;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Future;

@Service
@CacheConfig(cacheNames = "template")
public class TemplateService extends BaseService {
    @Autowired
    PageTemplateRepository templateRepository;

    @Autowired
    PageContentItemRepository pageContentItemRepository;

    @Autowired
    private RedisTemplate redisTemplate;


    @Autowired
    EntityManagerFactory emf;

    @Value("${web.upload-img-path}")
    private String uploadPath;


    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //@Cacheable(key = "#root.target.uploadPath + #p0")
    @Cacheable(key = "'template-'.concat(#p0)")
    public PageTemplate getTemplateDetail(long templateId){

        PageTemplate tmp=templateRepository.getTemplateDetail(templateId);
        return tmp;
        //return templateRepository.findByCompanycode(companyCode);
    }
    public CallResult getCorpCurrentTemplateDetail(String corpId){
        QPageTemplate qPageTemplate=QPageTemplate.pageTemplate;
        Long curTemplateId=
        queryFactory.select(qPageTemplate.id)
                .from(qPageTemplate)
                .where(qPageTemplate.companycode.eq(corpId)
                        .and(qPageTemplate.templatetype.eq(TemplateType.Current.ordinal())))
                .fetchOne();
        if(curTemplateId==null || curTemplateId==0){
            return CallResult.error("找不到当前模板！");
        }
        PageTemplate tmp=templateRepository.getTemplateDetail(curTemplateId);
        return CallResult.ok(tmp);
    }
    /*
    *我的模板列表
     */
    public List<MyTemplate> getMyTemplateList(String corpId){
        List<Tuple> cutList=templateRepository.getGroupedTemplateCount(corpId);
        List<PageTemplate> list= templateRepository.findGroupedTop3ByPageTemplateType(corpId);
        List<MyTemplate> mylist=new ArrayList<>();
        //组装List<MyTemplate>
        for(PageTemplate item:list){
            Integer type=item.getTemplatetype();
            //add mytemplate if no
            if(mylist.stream().filter(i-> i.getType().equals(type)).count()==0){
                MyTemplate myTmp=new MyTemplate(type,0L);
                Optional<Tuple> cutT= cutList.stream()
                        .filter(i-> i.get(0,Integer.class).equals(type))
                        .findFirst();

                cutT.ifPresent(i->myTmp.setCount(i.get(1,Long.class)));
                mylist.add(myTmp);
            }
            //item to mytemplate.list
            for(MyTemplate t:mylist){
                if(t.getType().equals(type)){
                    t.getList().add(item);
                }
            }
        }
        return mylist;
    }
    //获取官方模板
    public  List<PageTemplate> getOfficialTemplate(){
        List<PageTemplate> list= templateRepository.findByTemplatetype(TemplateType.Official.ordinal());
        return list;
    }
    //获取企业所有模板
    public List<PageTemplate> getTemplateList(String corpId){
        List<PageTemplate> list= templateRepository.findByCompanycodeOrderByCreatedDesc(corpId);
        return list;
    }
    /*
    *按分类获取企业模板
    * @templatetype 0: 临时快照1：官方预定义模板: 2：快照3:当前使用4：自定义模板(发布过的)
    * */
    public List<PageTemplate> getTemplateList(String corpId,int templatetype){
        List<PageTemplate> list= templateRepository.findByCompanycodeAndTemplatetypeOrderByCreatedDesc(corpId,templatetype);
        return list;
    }

    /*
    *生成模板快照
    * @templateId 选择的官方模板id
    * */
    public CallResult genTemplateSnap(long templateId,String companyCode){

        if(StringUtils.isEmpty(companyCode)) return CallResult.error("公司编号不能为空！");

        PageTemplate myOfficialTemplate= templateId==0?new PageTemplate():
                templateRepository.getTemplateDetail(templateId);

        if(myOfficialTemplate==null) return CallResult.error("模板数据不存在！");
//        EntityManagerFactory emf =
//                Persistence.createEntityManagerFactory("TemplateService");
        EntityManager em = emf.createEntityManager();
        em.detach(myOfficialTemplate);
        String templateName=myOfficialTemplate.getName()==null?"空白模板 草稿":myOfficialTemplate.getName()+ " 草稿";
        int originTemplateType=myOfficialTemplate.getTemplatetype()==null?
                TemplateType.Official.ordinal(): myOfficialTemplate.getTemplatetype();
        Timestamp now=new Timestamp(System.currentTimeMillis());
        myOfficialTemplate.setCompanycode(companyCode);
        myOfficialTemplate.setTemplatetype(TemplateType.Snapshoot.ordinal());
        myOfficialTemplate.setMasterid(myOfficialTemplate.getId());
        myOfficialTemplate.setId(IdWorker.nextId());
        myOfficialTemplate.setName(templateName);
        myOfficialTemplate.setUpdated(now);
        myOfficialTemplate.setCreated(now);

        //得到当前公司的isv
        List<PageContentItem> isvs = pageContentItemRepository.findByCompanycodeAndType(companyCode,ModuleType.dingtalkISV);

        List<PageModule> modules=myOfficialTemplate.getModules();
        EntityTransaction transaction = null;
        try{
            transaction = em.getTransaction();
            transaction.begin();
            for(PageModule m:modules){
                //作为新生成模块Id
                long moduleId=IdWorker.nextId();
                m.setId(moduleId);
                m.setTemplateid(myOfficialTemplate.getId());
                m.setCompanycode(companyCode);
                m.setCreated(now);
                //复制保存moduleItems内容
                List<ModuleItemDto> mitems= m.getModuleItems();
                if(originTemplateType==TemplateType.Official.ordinal()){//从官方模板创建快照
                    int isvSort=0;
                    //isv导入当前公司的数据到模块关系
                    if((m.getType().equals(ModuleType.dingtalkISV) || m.getType().equals(ModuleType.doMyself)) && isvs!=null) {
                        for (PageContentItem isv : isvs) {
                            em.persist(new PageModuleItem(IdWorker.nextId(), moduleId, isv.getId(),
                                    ContentRefType.Self.ordinal(), isvSort++, companyCode, now));
                        }
                    }else{//其它模块复制模块关系表 即：指向官方内容的引用
                        for(ModuleItemDto mi:mitems){
                            if(!mi.getType().equals(ModuleType.dingtalkISV) && !mi.getType().equals(ModuleType.doMyself)){
                                em.persist(new PageModuleItem(IdWorker.nextId(),moduleId,mi.getContentid(),
                                        ContentRefType.Official.ordinal(),mi.getSort(),companyCode,now));
                            }
                        }
                    }
                }else{//从自己模板创建快照
                    for(ModuleItemDto mi:mitems){
                        em.persist(new PageModuleItem(IdWorker.nextId(),moduleId,mi.getContentid(),
                                mi.getReftype(),mi.getSort(),companyCode,now));
                    }
                }

                //保存模块
                em.persist(m);
            }
            em.persist(myOfficialTemplate);

            em.flush();
            em.clear();
            transaction.commit();

            return CallResult.ok(myOfficialTemplate.getId());
        }catch (RuntimeException e) {
            if ( transaction != null &&
                    transaction.isActive()) {
                transaction.rollback();
            }
            throw e;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    @CacheEvict(key = "'template-'.concat(#p0)")
    @Transactional
    public CallResult updateTemplateName(long templateId,String name){
        QPageTemplate qTemplate=QPageTemplate.pageTemplate;
        long i=
                queryFactory.update(qTemplate).where(qTemplate.id.longValue().eq(templateId))
                        .set(qTemplate.name,name)
                        .execute();
        return CallResult.code((int)i);
    }

    @Async
    @Transactional(rollbackFor=Exception.class)
    public Future<CallResult> saveThumbFromBase64(long templateId, String base64Str) throws Exception{
        try{
            if(templateId==0) return new AsyncResult<>(CallResult.error("temlateId不能为空！"));

            System.out.print("thread:"+Thread.currentThread().getName());

            String path=uploadPath+ File.separator +  "template";
            File fpath = new File(path);
            if(!fpath.isDirectory())
                fpath.mkdirs();
            //删除旧缩略图
            java.io.File[] files=fpath.listFiles((f)-> f.getName().startsWith(templateId+"-"));
            for(File f:files){
                f.delete();
            }
            String fileName=templateId+"-"+System.currentTimeMillis()*1000+".jpg";

            Base64 base64 = new Base64();
            byte[] bytes = base64.decodeBase64(base64Str.replaceFirst("data:image/png;base64,","").getBytes());
            //统一压缩
            InputStream input = new ByteArrayInputStream(bytes);
            Thumbnails.of(input).size(800,800)
                    .outputFormat("jpg")
                    .outputQuality(0.5)
                    .toFile(path+File.separator+fileName);
            //更新数据库
            Timestamp now=new Timestamp(System.currentTimeMillis());
            String saveUrl="image/template/"+fileName;
            QPageTemplate qTemplate=QPageTemplate.pageTemplate;
            queryFactory.update(qTemplate)
                    .set(qTemplate.thumb,saveUrl)
                    .set(qTemplate.updated,now)
                    .where(qTemplate.id.longValue().eq(templateId))
                    .execute();
            /*超过800才压缩
            InputStream inputImg = new ByteArrayInputStream(bytes);
            BufferedImage image = ImageIO.read(inputImg);
            if(image.getWidth()>800 || image.getHeight()>800){
                Thumbnails.of(input).size(800,800)
                        .outputFormat("jpg")
                        .outputQuality(0.5)
                        .toFile(savePath);
            }else {
                ImageIO.write(image,"jpg",new File(savePath));
            }
            */
//            if(true)
//            throw new Exception("error1");
            //update cache
            PageTemplate tmp= (PageTemplate)redisTemplate.opsForValue().get("template-"+templateId);
            if(tmp!=null){
                tmp.setThumb(saveUrl);
                redisTemplate.opsForValue().set("template-"+templateId,tmp);
            }
            return new AsyncResult<>(CallResult.ok(saveUrl));
        }catch (Exception ex){
            logger.error("生成缩略图出错:", ex);
            throw ex;
            //return CallResult.error("生成缩略图出错！");
        }

    }

    @CacheEvict(key = "'template-'.concat(#p0)")
    @Transactional
    public CallResult releaseTemplate(long templateId,String corpId){
        QPageTemplate qPageTemplate=QPageTemplate.pageTemplate;

        //已发布改为未发布
        queryFactory.update(qPageTemplate)
                .set(qPageTemplate.isrelease,false)
                .set(qPageTemplate.iscurrent,false)
                .set(qPageTemplate.templatetype,TemplateType.Custom.ordinal())
                .where(qPageTemplate.templatetype.eq(TemplateType.Current.ordinal())
                        .and(qPageTemplate.companycode.eq(corpId)))
                .execute();
        //更改发布
        long i=
        queryFactory.update(qPageTemplate)
                .set(qPageTemplate.isrelease,true)
                .set(qPageTemplate.iscurrent,true)
                .set(qPageTemplate.templatetype,TemplateType.Current.ordinal())
                .where(qPageTemplate.templatetype.ne(TemplateType.Current.ordinal())
                        .and(qPageTemplate.id.eq(templateId).and(qPageTemplate.companycode.eq(corpId))))
                .execute();

        return i>0?CallResult.ok():CallResult.error("发布失败！");

    }
    @CacheEvict(key = "'template-'.concat(#p0)")
    @Transactional(rollbackFor=Exception.class)
    public CallResult deleteTemplate(long templateId, String corpId){
        QPageTemplate qTemplate=QPageTemplate.pageTemplate;
        QPageModule qModule=QPageModule.pageModule;
        QPageModuleItem qModuleItem=QPageModuleItem.pageModuleItem;

//        Integer templateType=
//        queryFactory.select(qTemplate.templatetype)
//                .from(qTemplate).where(qTemplate.id.eq(templateId))
//                .fetchOne();
//        if(templateType==null) return CallResult.error("模板不存在！");
//        if(templateType.equals(TemplateType.Current.ordinal())) return CallResult.error("模板正在使用中！");

        //del模板 过滤掉已发布
        long i=
        queryFactory.delete(qTemplate)
                .where(qTemplate.id.longValue().eq(templateId)
                        .and(qTemplate.companycode.eq(corpId))
                        .and(qTemplate.templatetype.ne(TemplateType.Current.ordinal())))
                .execute();
        if(i==0) return CallResult.error("无法删除，操作失败！");
        //del模块内容关系, 内容不删除
        queryFactory.delete(qModuleItem)
                    .where(qModuleItem.moduleid.in(
                            queryFactory.select(qModule.id).from(qModule).where(qModule.templateid.longValue().eq(templateId)
                                    .and(qModuleItem.companycode.eq(corpId)))
                    )).execute();
        //del模块
        queryFactory.delete(qModule)
                .where(qModule.templateid.longValue().eq(templateId).and(qModule.companycode.eq(corpId)))
                .execute();


        return CallResult.ok();
    }
}
